
do --- to-number-scan
  local ffi = require("ffi")
  local bit = require("bit")

  ffi.cdef[[
  double strtod(const char *, char **);
  ]]

  local t = {
    -- errors
    false, "",
    false, " ",
    false, "+",
    false, "z",
    false, ".",
    false, ".z",
    false, "0.z",
    false, ".0z",
    false, "0xz",
    false, "0x.z",
    false, "0x0.z",
    false, "0x.0z",
    false, ".e5",
    false, ".p4",
    false, "1.p4",
    false, "1.p+4",
    false, "0x1.e+4",
    false, "infi",
    false, "+ 1",
    false, "- 9",
    -- misc
    0x3ff0000000000000ULL, " \t\n\v\f\r 1",
    -- inf/nan
    0x7ff0000000000000ULL, "iNF",
    0xfff0000000000000ULL, "-Inf",
    0x7ff0000000000000ULL, "+iNfInItY",
    0xfff0000000000000ULL, "-INFINITY",
    0xfff8000000000000ULL, "naN",
    0xfff8000000000000ULL, "+NaN",
    0xfff8000000000000ULL, "-nAn",
    -- smallest/largest numbers
    0x0000000000000000ULL, "0e1000",
    0x0000000000000000ULL, "0e-1000",
    0x0000000000000000ULL, "0x0p2000",
    0x0000000000000000ULL, "0x0p-2000",
    0x7ff0000000000000ULL, "1e1000",
    0x0000000000000000ULL, "1e-1000",
    0xfff0000000000000ULL, "-1e1000",
  -- wrong for DUALNUM: 0x8000000000000000ULL, "-1e-1000",
    0x7ff0000000000000ULL, "0x1p2000",
    0x0000000000000000ULL, "0x1p-2000",
    0xfff0000000000000ULL, "-0x1p2000",
  -- wrong for DUALNUM: 0x8000000000000000ULL, "-0x1p-2000",
    0x0010000000000000ULL, "2.2250738585072014e-308",
    0x7fefffffffffffffULL, "1.7976931348623158e+308",
    0x8000b8157268fdafULL, "-1e-309",
    0x000ac941b426dd3bULL, "1.5e-308",
    0x000ac941b426dd3bULL, "0x0.ac941b426dd3b7p-1022",
    0x0000000000000001ULL, "4.9406564584124654e-324",
    0x000f9c7573d7fe52ULL, "2.171e-308",
    0x241d21ecf36d4a22ULL, "1.0020284025808569e-134",
    0x0000000000000001ULL, "0x1p-1074",
    0x0000000000000000ULL, "0x1p-1075",
    0x0000000000000000ULL, "0x1p-1076",
    0x0000000000000000ULL, "0x0.ffffffffffffffffffffffffffp-1075",
    0x0000000000000000ULL, "0x1.00000000000000000000000000p-1075",
    0x0000000000000001ULL, "0x1.00000000000000000000000001p-1075",
    0x7fe0000000000000ULL, "0x1p1023",
    0x7ff0000000000000ULL, "0x1p1024",
    0x7ff0000000000000ULL, "0x1p1025",
    0x7ff0000000000000ULL, "0x3p1023",
    0x7ff0000000000000ULL, "0x3.ffffffffffffecp1023",
    0xfff0000000000000ULL, "-0xf7dcba98765432p969",
    0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000000p1023",
    0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000001p1023",
    0x7fefffffffffffffULL, "0x1.fffffffffffff7ffffffffffffp1023",
    0x7ff0000000000000ULL, "0x1.fffffffffffff8000000000000p1023",
    0x7fefffffffffffffULL, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0",
    0x7fefffffffffffffULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.999",
    0x7ff0000000000000ULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792.0",
    0x3ff0000000000000ULL, "0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000p-1028",
    0x1214e2995454ee0bULL, "0."..string.rep("0", 220).."1"..string.rep("4", 800),
    -- http://www.exploringbinary.com/15-digit-quick-and-dirty-conversions-dont-round-trip/
    0x04409cf3929ffbc3ULL, "3.409452297963e-288",
    0x7fe02b4782a6c378ULL, "9.08344e+307",
    0x6e05e258a3929ee5ULL, "9.88819e+221",
    -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/
    0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875",
    0x42c0000000000002ULL, "3.518437208883201171875e13",
    0x404f44abd5aa7ca4ULL, "62.5364939768271845828",
    0x3e0bd5cbaef0fd0cULL, "8.10109172351e-10",
    0x3ff8000000000000ULL, "1.50000000000000011102230246251565404236316680908203125",
    0x433fffffffffffffULL, "9007199254740991.4999999999999999999999999999999995",
    0x7ecd2e77eb6e3fadULL, "6.253649397682718e+302",
    0x7ecd2e77eb6e3fadULL, "6.2536493976827180e+302",
    -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/
    0x43405e6cec57761aULL, "9214843084008499",
    0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875",
    0x44997a3c7271b021ULL, "30078505129381147446200",
    0x4458180d5bad2e3eULL, "1777820000000000000001",
    0x3fe0000000000002ULL, "0.500000000000000166547006220929549868969843373633921146392822265625",
    0x3fe0000000000002ULL, "0.50000000000000016656055874808561867439493653364479541778564453125",
    0x3fd92bb352c4623aULL, "0.3932922657273",
    -- http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
    0x0010000000000000ULL, "2.2250738585072012e-308",
    -- http://www.exploringbinary.com/incorrectly-rounded-subnormal-conversions-in-java/
    0x0000000008000000ULL, "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125e-316",
    0x0000000000010000ULL, "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875e-319",
    0x0000800000000100ULL, "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125e-310",
    0x0000000000010800ULL, "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875e-319",
    -- EGLIBC 2.16 tests
    0x4028b0a3d70a3d71ULL, "12.345",
    0x441ac4da03bc47e4ULL, "12.345e19",
    0xc197d78400000000ULL, "-.1e+9",
    0x3fc0000000000000ULL, ".125",
    0x4415af1d78b58c40ULL, "1e20",
    0x0000000000000000ULL, "0e-19",
    0x3051144f2d9a718bULL, "5.9e-76",
    0x4024000000000000ULL, "0x1.4p+3",
    0x4024000000000000ULL, "0xAp0",
    0x4024000000000000ULL, "0x0Ap0",
    0x4024000000000000ULL, "0x0A",
    0x4064000000000000ULL, "0xA0",
    0x4064000000000000ULL, "0x0.A0p8",
    0x4064000000000000ULL, "0x0.50p9",
    0x4064000000000000ULL, "0x0.28p10",
    0x4064000000000000ULL, "0x0.14p11",
    0x4064000000000000ULL, "0x0.0A0p12",
    0x4064000000000000ULL, "0x0.050p13",
    0x4064000000000000ULL, "0x0.028p14",
    0x4064000000000000ULL, "0x0.014p15",
    0x4064000000000000ULL, "0x00.00A0p16",
    0x4064000000000000ULL, "0x00.0050p17",
    0x4064000000000000ULL, "0x00.0028p18",
    0x4064000000000000ULL, "0x00.0014p19",
    0x0008000000000000ULL, "0x1p-1023",
    0x0008000000000000ULL, "0x0.8p-1022",
    0x3ff0000140000000ULL, "0x80000Ap-23",
    0x0000000000000000ULL, "1e-324",
    0x4370000000000000ULL, "0x100000000000008p0",
    0x4370000000000000ULL, "0x100000000000008.p0",
    0x4370000000000000ULL, "0x100000000000008.00p0",
    0x43f0000000000000ULL, "0x10000000000000800p0",
    0x43f0000000000001ULL, "0x10000000000000801p0",
    -- Fuzzing
    0x699783fbf2d24ea5ULL, "449999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999",
    0x43f158e460913d00ULL, "2e19",
  }

  local function tohex64(x)
    return "0x"..bit.tohex(tonumber(x/2LL^32))..bit.tohex(tonumber(x%2LL^32)).."ULL"
  end

  local conv = tonumber

  if arg and arg[1] == "strtod" then
    local e = ffi.new("char *[1]")
    function conv(s)
      local d = ffi.C.strtod(s, e)
      return (e[0][0] == 0 and #s ~= 0) and d or nil
    end
  end

  local u = ffi.new("union { double d; uint64_t x; }")

  for i=1,#t,2 do
    local y, s = t[i], t[i+1]
    local d = conv(s)
    local ok
    if d == nil then
      ok = (y == false)
    else
      u.d = d
      ok = (y == u.x)
    end
    if not ok then
      io.write('FAIL: "', s, '"\n GOT: ', d and tohex64(u.x) or "nil", "   OK: ", y and tohex64(y) or "nil", "\n\n")
  --      print("  "..tohex64(u.x)..", \""..s.."\",")
    end
  end
end

